﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

using agree.schema;

using alib.Array;
using alib;
using alib.Character;
using alib.String;
using alib.IO;
using alib.Enumerable;
using alib.Concurrency;
using alib.Collections;
using alib.Collections.ReadOnly;
using alib.Reflection;
using alib.Debugging;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class LazyTfsDerivation : identity_base, IDerivation
	{
		public LazyTfsDerivation(IIdentity prv, IChartLicense license, IReadOnlyList<IDerivation> q, StartSymbol[] ss_matches)
			: base(prv)
		{
			this.dvo = new DerivationHelper(license, q, ss_matches);
		}

		public LazyTfsDerivation(IIdentity prv, IChartObj co, IReadOnlyList<IDerivation> q)
			: this(prv, co.ChartLicense, q, co.MatchedStartSymbols)
		{
			if (co.IsRemove())
				throw new Exception();
		}

		///////////////////////////////////////////////////////////////////////
		/// 
		protected DerivationHelper dvo;
		public IChartLicense ChartLicense { [DebuggerStepThrough] get { return dvo.license; } }
		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public IReadOnlyList<IDerivation> Daughters { [DebuggerStepThrough]  get { return dvo.daughters; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public ulong DerivationHash { [DebuggerStepThrough] get { return dvo.DerivationHash(this); } }
		public Double Score(MaxEntModel model) { return dvo.Score(this, model); }
		public Double ParseSelectionScore { [DebuggerStepThrough] get { return Score(null); } }
		/// 
		///////////////////////////////////////////////////////////////////////


		/// fix fix -- lth seems fragile for IChartObj/derivs. what if you pause in the debugger during parsing: a derivation
		/// will be rendered and cached... what if retroactive packing then kills the chartobj .. not sure ..

		///////////////////////////////////////////////////////////////////////
		/// 
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		Tfs dtfs;
		public Tfs DerivationTfs()
		{
			var inst = (Instance)this.ChartLicense;

			var _tmp = dtfs;
			if (_tmp == null)
			{
				if ((_tmp = DerivationFuncs.reconstitute_tfs(this, inst.fsu)) == null || !dvo._revalidate(_tmp))
					_tmp = inst.td.NullTfs;
				this.dtfs = _tmp;
			}
			return _tmp is NullTfs ? null : _tmp;
		}
		/// 
		///////////////////////////////////////////////////////////////////////

		///////////////////////////////////////////////////////////////////////
		/// 
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public StartSymbol[] MatchedStartSymbols { get { return dvo.ss_matches; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public StartSymbol ItemStartSymbol { get { return dvo.get_ss(this); } }
		/// 
		///////////////////////////////////////////////////////////////////////


		///////////////////////////////////////////////////////////////////////
		/// 
		public override String ToString()
		{
			var s = String.Format("{0} {1} {2}",
				this.GetType()._Name(),
				ChartLicense.Name,
				this.Text().DoubleQuote());

			var score = this.ParseSelectionScore;
			if (!Double.IsNaN(score))
				s += String.Format("\r\n{0:N5}", score);

			return s;
			//return this.ToString(false);
		}
		/// 
		///////////////////////////////////////////////////////////////////////
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// note: these are currently not marked for IRootDerivation
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class StandaloneLazyTfsDerivation : LazyTfsDerivation
	{
		public StandaloneLazyTfsDerivation(IRtParent parent, IChartLicense license, IDerivation[] q)
			: base(parent, license, q, null)
		{
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public static IDerivation Create(IRtParent parent, String s)
		{
			s = s.Replace("\\\"", "\"");
			int i = 0;
			String ff = null;
			IDerivation tr = build_tree(parent, s, ref i, ref ff);
			return tr;
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		static IDerivation build_tree(IRtParent ctrl, String s, ref int i, ref String ff)
		{
			String body = null;
			String form = null;
			List<IDerivation> lds = new List<IDerivation>();

			EntryMgr em = ((TfsUnifier)P.TfsUnifier.GetValue(ctrl)).em;

			int ii = i;
			while (i < s.Length)
			{
				Char ch = s[i++];
				if (ch == '(')
				{
					body = body ?? s.Substring(ii, i - ii - 1);
					IDerivation dtr = build_tree(ctrl, s, ref i, ref form);
					if (ii == 0)
						return dtr;
					if (dtr != null)
					{
						lds.Add(dtr);
					}
				}
				else if (ch == ')')
				{
					body = body ?? s.Substring(ii, i - ii - 1);

					IDerivation skel = null;
					if (body[0] != '\"')
					{
						String[] rgs = body.Split(Charset.sp, StringSplitOptions.RemoveEmptyEntries);

						if (rgs.Length == 1)
						{
							/// root condition
							return lds[0];
						}

						ChartSpan sp = new ChartSpan(int.Parse(rgs[3]), int.Parse(rgs[4]) - 1);
						var lic = (IChartLicense)em[rgs[1]];
						int id = int.Parse(rgs[0]);

						if (form != null)
						{
							skel = new ctl_lexref_itok_form(ctrl, (LexicalEntry)lic, sp, form, null);
							//skel.Id = id;
						}
						else
						{
							var d = new StandaloneLazyTfsDerivation(ctrl, lic, lds.ToArray());
							//d.Id = id;
#if true
							throw new Exception();
#else
							skel = d;
#endif
						}
						//skel.Score = double.Parse(rgs[2]);
					}
					else
					{
						int ix_sp = body.IndexOf(' ');
						if (ix_sp != -1)
							body = body.Remove(ix_sp);
						ff = body.Trim(Charset.dq);
					}
					return skel;
				}
			}
			throw new Exception("Error in the format of the input string while reconstituting a derivation.");
		}
	};
}